#include <math.h>
#include <sstream>
#include <iostream>
#include <string.h>
#include "Pipeline/Config.h"
#include "Pipeline/Output.h"
#include "Pipeline/Polygon.h"
#include "Pipeline/Camera.h"
#include "Pipeline/Color.h"
#include "Pipeline/Point.h"
#include "Test.h"

/*********************************************/
void drawDot()
{
	Config::Instance()->parseFile("Config.cfg");
	bmpOutput		output;
	Color			color( 255, 0, 0 );
	Point3D			A( 250.0f, 250.0f, 0.0f, color );
	Camera			cam( &output );

	output.setOutputFile("./Output/output.bmp");
	cam.drawPoint2D(A, 5);
	cam.flush( BUFFER_FRAME );
}
/*********************************************/
void drawSinglePoint()
{
	Config::Instance()->parseFile("Config.cfg");
	bmpOutput		output;
	Color			color( 255, 0, 0 );
	Point3D			A( 250.0f, 250.0f, 0.0f, color );
	Camera			cam( &output );

	output.setOutputFile("./Output/output.bmp");
	cam.drawPoint2D( A );
	cam.flush( BUFFER_FRAME );
}
/*********************************************/
void drawSingleLine()
{
	Config *cfg = Config::Instance();
	cfg->parseFile( "Config.cfg" );

	bmpOutput		output;
	Camera			cam( &output );
	Point3D			A( 100.0f, 250.0f, 0.0f );
	Point3D			B( 400.0f, 350.0f, 0.0f );
	Color			color1( 255, 0, 0 );
	Color			color2( 0, 0, 255 );
	A.setColor(color1);
	B.setColor(color2);
	Line3D			l(A,B);

	cam.clear( BUFFER_FRAME );

	output.setOutputFile("./Output/output.bmp");
	cam.drawLine2D( l );
	cam.flush( BUFFER_FRAME );
}
/*********************************************/
void drawSinglePolygonDoubleCamera()
{
	Config *cfg = Config::Instance();
	cfg->parseFile( "Config.cfg" );

	Polygon			p;
	bmpOutput		output1, output2;
	Camera			cam1( &output1 );
	Camera			cam2( &output2 );

	Point3D		A( 1.0f, 0.0f, 0.0f );
	Point3D		B( 0.0f, 3.0f, 0.0f );
	Point3D		C( 0.0f, 0.0f, 1.0f );
	Color		color1( 0, 0, 255 );
	Color		color2( 0, 255, 0 );
	Color		color3( 255, 0, 0 );
	
	p.setPoint( 0, A );
	p.setPoint( 1, B );
	p.setPoint( 2, C );
	p.setColor( 0, color1 );
	p.setColor( 1, color2 );
	p.setColor( 2, color3 );

	cam2.setViewParameters( Point3D(0.0f,2.0f,2.0f), Point3D(0.0f,0.0f,0.0f) );

	output1.setOutputFile("./Output/outputCam1.bmp");
	output2.setOutputFile("./Output/outputCam2.bmp");
	cam1.drawPolygon3D( p );
	cam2.drawPolygon3D( p );

	cam1.flush( BUFFER_FRAME );
	cam2.flush( BUFFER_DEPTH );
}
/*********************************************/
void drawSinglePolygon()
{
	Config *cfg = Config::Instance();
	cfg->parseFile( "Config.cfg" );

	Polygon			p;
	bmpOutput		output;
	Camera			cam( &output );

	Point3D		A( 1.0f, 0.0f, 0.0f );
	Point3D		B( 0.0f, 3.0f, 0.0f );
	Point3D		C( 0.0f, 0.0f, 1.0f );
	Color		color1( 0, 0, 255 );
	Color		color2( 0, 255, 0 );
	Color		color3( 255, 0, 0 );
	
	p.setPoint( 0, A );
	p.setPoint( 1, B );
	p.setPoint( 2, C );
	p.setColor( 0, color1 );
	p.setColor( 1, color2 );
	p.setColor( 2, color3 );

	output.setOutputFile("./Output/output.bmp");
	cam.drawPolygon3D( p );
	cam.flush( BUFFER_FRAME );
}
/*********************************************/
void rotateSinglePolygon()
{
	Polygon		p;

	Config *cfg = Config::Instance();
	cfg->parseFile( "Config.cfg" );
	
	bmpOutput		outputTest;
	Camera			cam( &outputTest );

	Point3D		A( 1.0f, 0.0f, 0.0f );
	Point3D		B( 0.0f, 1.0f, 0.0f );
	Point3D		C( 0.0f, 0.0f, 1.0f );
	Color	color1( 0, 0, 255 );
	Color	color2( 0, 255, 0 );
	Color	color3( 255, 0, 0 );
	
	p.setPoint( 0, A );
	p.setPoint( 1, B );
	p.setPoint( 2, C );
	p.setColor( 0, color1 );
	p.setColor( 1, color2 );
	p.setColor( 2, color3 );

	for ( uint16 i = 0; i<180; i++ ) {
		std::ostringstream output;
		fl64 radians = i*0.0174532925;
		fl64 x = cos(radians)*2;
		fl64 y = sin(radians)*2;

		Point3D		eye( y, x, 1.0f );
		Point3D		view( 0.0f, 0.0f, 0.0f );
		cam.setViewParameters( eye, view );
		cam.clear(BUFFER_FRAME);
		cam.clear(BUFFER_DEPTH);

		std::cout << "** Frame: "  << "/Output/output" << i << ".bmp" << std::endl;

		output << "./Output/output" << i << ".bmp";
		outputTest.setOutputFile(output.str());

		cam.drawPolygon3D( p );
		cam.flush( BUFFER_FRAME );
	}
	
	std::cout << "Done." << std::endl;
}
/*********************************************/
int main(int args, char* argv[])
{
/*	ImageBuffer<uint32>	test(500,500);

	for ( uint32 i = 0; i<500; i++ ) {
		test.setPixel(i,i,-1);
	}

	for ( uint32 i = 0; i<500; i++ ) {
		if ( test.getPixel(i,i) != -1) {
			std::cout << "error" << std::endl;
		}
	}

	test.clear(0);
*/

	if ( args > 1 ) {
		if ( strcmp(argv[1],"rotate") == 0) rotateSinglePolygon();
		else if (strcmp(argv[1],"line") == 0) drawSingleLine();
		else if (strcmp(argv[1],"polygon") == 0) drawSinglePolygon();
		else if (strcmp(argv[1],"doubleCam") == 0) drawSinglePolygonDoubleCamera();
		else if (strcmp(argv[1],"point") == 0) drawSinglePoint();
		else if (strcmp(argv[1],"dot") == 0) drawDot();
		else std::cout << "Invalid parameter" << std::endl;
	} else {
		std::cout << "No test rendering option found!" << std::endl;
		std::cout << "********" << std::endl << std::endl;
		std::cout << "Current options: " << std::endl;
		std::cout << "'rotate'" << std::endl;
		std::cout << "'point'" << std::endl;
		std::cout << "'dot'" << std::endl;
		std::cout << "'doubleCam'" << std::endl;
		std::cout << "'polygon'" << std::endl;
		std::cout << "'line'" << std::endl;
	}
}